home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DDJMAG
/
DDJ9212.ZIP
/
fortran.asc
< prev
next >
Wrap
Text File
|
1992-11-30
|
14KB
|
622 lines
_WHY C++ WILL REPLACE FORTRANB_
by Thomas Keffer
[LISTING ONE]
// This class holds a reference count and a pointer to the vector data
class DataBlock {
private:
unsigned short refs; // Number of references
void* array; // Pointer to raw, untyped data
public:
DataBlock(unsigned nelem, size_t elemsize)
{array = new char[nelem*elemsize]; refs = 1; }
~DataBlock() { delete array; }
void addReference() {refs++;}
unsigned short removeReference() {return --refs;}
void* data() {return array;}
};
[LISTING TWO]
class DoubleVec {
DataBlock* block; // Pointer to the DataBlock
double* begin; // Start of data
unsigned npts; // Length of the vector
int step; // Stride length
DoubleVec(const DoubleVec&, int, unsigned, int); // For slices
public:
DoubleVec(unsigned n, double val); // n elements, initialized to val
DoubleVec(const DoubleVec& a); // Copy constructor
~DoubleVec();
DoubleVec slice(int start, int stride, unsigned lgt) const;
unsigned length() const {return npts;}
int stride() const {return step;}
double& operator()(int i) const {return begin[i*step];}
DoubleVec& operator=(const DoubleVec& v);
};
// Copy constructor:
DoubleVec::DoubleVec(const DoubleVec& a)
{
block = a.block;
block->addReference();
npts = a.npts;
begin = a.begin;
step = a.step;
}
// Destructor:
DoubleVec::~DoubleVec()
{
if (block->removeReference()==0)
delete block;
}
[LISTING THREE]
// Construct a vector that is a slice of an existing vector:
DoubleVec::DoubleVec(const DoubleVec& v, int start, unsigned n, int str)
{
block = v.block;
block->addReference();
npts = n;
begin = v.begin + start*v.stride; // Add start points
stride = str*v.stride; // Accumulate strides
}
[LISTING FOUR]
class DoubleMatrix : private DoubleVec {
unsigned ncols; // Number of columns
unsigned nrows; // Number of rows
public:
DoubleMatrix();
DoubleMatrix(unsigned rows, unsigned cols, double initval);
DoubleMatrix(const DoubleMatrix& m); // Reference to m will be made
unsigned cols() const {return ncols;}
unsigned rows() const {return nrows;}
DoubleVec col(unsigned j) const // Return col as slice
{ return DoubleVec::slice(j*nrows, 1, nrows); }
DoubleVec row(unsigned i) const; // Return row as slice
{ return DoubleVec::slice(i, nrows, ncols); }
DoubleVec diagonal() const; // Return diagonal as slice
double& operator()(int i, int j) const; // Subscripting
... // Other operators
};
[LISTING FIVE]
class LUDecomp : private DoubleMatrix {
int* permute; // Row permutations
public:
LUDecomp(const DoubleMatrix&);
~LUDecomp() { delete permute; }
int isSingular() const;
friend double determinant(const LUDecomp&);
friend DoubleMatrix inverse(const LUDecomp&);
friend DoubleVec solve(const LUDecomp&, const DoubleVec&);
};
[LISTING SIX]
class FFTServer {
unsigned npts;
ComplexVec theRoots;
void calculateRoots();
public:
FFTServer(unsigned n = 0) {setOrder(n);}
void setOrder(unsigned n)
{ npts = n; calculateRoots(); }
ComplexVec fourier(const ComplexVec& v){
if(v.length() != npts) setOrder(v.length());
ComplexVec tran;
// ... (calculate transform, put it in tran)
return tran;
}
};
Example 1
ComplexVec b; // Declare a complex vector
cin >> b; // Read it in
FFTServer s; // Allocate an FFT server
// Calculate the transform of b:
ComplexVec theTransform = s.fourier(b);
cout << theTransform; // Print it out
Example 2
(a)
DoubleVec a; // Null vector - no elements at all, but can be resized
DoubleVec b(8); // 8 elements long, uninitialized
DoubleVec c(8,1); // 8 elements, initialized to 1.0
DoubleVec d(8,1,2); // 8 elements, initialized to 1, 3, 5, ...
(b)
b = 2.0; // Set all elements of b to 2
b = c + d; // Set b to the sum of c and d
b *= 2; // Multiply each element in b by 2.
(c)
b[2] = 4.0; // Set the 3'rd element of b to 4.0.
c[1] = b[3]; // Set the 2'nd element of c to the 4'th element of b
(d)
DoubleVec a(10, 0); // 10 element vector
for(int i = 0; i<10; i+=2)
a[i] = 1;
Example 3
(a)
a.slice(0, 2) = 1; // Starting with element 0; set every other element to 1
(b)
class DoubleVec {
...
public:
...
operator DoubleSlice(); // For type conversion
DoubleSlice slice(int start, int step, unsigned N) const;
};
// The "helper class":
class DoubleSlice {
DoubleVec* theVector;
int startElement;
unsigned sliceLength;
int step;
public:
...
friend DoubleVec operator+(const DoubleSlice&, const DoubleSlice&);
...
};
(c)
DoubleVec b(10, 0), c(10, 1);
DoubleVec d = b.slice(0, 2) + c.slice(1, 2);
(d)
DoubleVec g = b + c; // DoubleVec to DoubleSlice type conversion occurs
Example 4
(a)
DoubleVec real(const ComplexVec&);
(b)
ComplexVec a(10, 0); // (0,0), (0,0), (0,0), ...
real(a) = 1.0; // (1,0), (1,0), (1,0), ...
Example 5
(a)
DoubleMatrix a(10, 10, 0); // 10 by 10 matrix, initialized to zero
a.row(3) = 1; // Set row 3 to 1
a.col(2) = a.col(4); // Copy column 4 to column 2
(b)
DoubleMatrix I(10, 10, 0); // 10x10 initialized to 0
I.diagonal() = 1; // Create an identity matrix
Example 6
Example 6
(a)
DoubleMatrix a(10, 10);
// ... (initialize a somehow)
// Construct the LU decomposition of a:
LUDecomp aLU(a);
// Now use it:
double det = determinant(aLU);
DoubleMatrix aInverse = inverse(aLU);
(b)
// 5 different sets of linear equations to be solved:
DoubleVec b[5], x[5];
// ... (set up the 5 vectors b and the 5 vectors x, each
// with 10 elements as per the matrix a above)
for(int i = 0; i < 5; i++)
x[i] = solve(aLU, b[i]);
(c) [SET THIS IN HELV, NOT PRESTIGE]
a xi = bi; i = 0, ..., 4.
(d)
DoubleMatrix a(10, 10);
// ... (initialize a)
// Calculate the inverse directly from a.
// A DoubleMatrix to LUDecomp type conversion takes place automatically:
DoubleMatrix aInverse = inverse(a);
(e)
DoubleMatrix aInverse = inverse(LUDecomp(a));
Example 7
ComplexVec timeVector(30);
FFTServer aServer; // Allocate a server
// Will automagically reconfigure for a vector of length 30:
ComplexVec spectrum = aServer.fourier(timeVector);
Example 8
class Force; // 1
class String { // 2
public:
String(double length, double tension, double density); // 3
void setPoints(int nx); // 4
void timeStep(double dt, const Force& force); // 5
DoubleVec displacement() const; // 6
private:
DoubleVec u; // 7
double cSquared;
double length;
};
Example 9
(a)
class Force {
public:
virtual DoubleVec value() = 0; // 1
};
(b)
class WindForceString : public Force {
public:
WindForceString( String& string, double dragCoeff );
void setVelocity(double windspeed);
virtual DoubleVec value(); // 1
private:
String& myString; // The string we are tracking
double wind; // Present wind speed.
double drag;
};
(c)
DoubleVec WindForceString::value()
{
// Get present string displacement:
DoubleVec d = string.displacement();
return -drag*wind*wind*d; // Some (bogus) calculation
}
Figure 1:
C++ Fortran
#include <dvec.h> parameter (M=8000)
#include <stdlib.h> double precision a(M), b(M)
#include <iostream.h> double precision c(M)
main(int argc, char* argv[]) { read(5,*) N, Niter
unsigned N = atoi(argv[1]); write(6,1000)Niter, N
unsigned Niter = atoi(argv[2]); 1000 format(i8,' iterations of ',
* i8, ' points each.')
cout << Niter << "iterations of "
<< N << " points each.\n"; do 50 j=1,N
a(j) = 3
DoubleVec a(N, 3), b(N, 5); 50 b(j) = 5
while(Niter--) do 100 i=1,Niter
DoubleVec c = a * b; do 100 j=1,N
} 100 c(j) = a(j) * b(j)
stop
end
Figure 2
(a)
#include <dgenfct.h>
#include <rstream.h>
class DTestMatrix : public DoubleGenMat {
public:
DTestMatrix(unsigned order);
};
class DTestRHS : public DoubleVec {
public:
DTestRHS(const DTestMatrix&);
};
double second();
double epslon(double);
const unsigned N = 90;
const unsigned long ops = 2.0*N*N*N/3.0 + 2.0*N*N;
void main(){
DTestMatrix a(N);
double norma = maxVal(abs(a));
DTestRHS b(a);
double t1 = second();
// Construct the LU Factorization:
DoubleGenFact fact(a);
t1 = second() - t1;
double t2 = second();
DoubleVec x = solve(fact, b);
t2 = second() - t2;
double total = t1+t2;
double mflops = ops / (1.0e6*total);
DoubleVec tol = a.product(x) - b;
double resid = maxVal(abs(tol));
double normx = maxVal(abs(x));
double eps = epslon(1.0);
double residn= resid / (N*norma*normx*eps);
cout << "Normalized residual = " << residn << NL;
cout << "Residual = " << resid << NL;
cout << "Machine precision = " << eps << NL;
cout << "Factorization time = " << t1 << NL;
cout << "Solution time = " << t2 << NL;
cout << "Total time = " << total << NL;
cout << "MFLOPS = " << mflops << NL;
}
DTestMatrix::DTestMatrix(unsigned n) : DoubleGenMat(n,n) {
long init = 1325;
for(int j=0; j<n; j++){
for(int i=0; i<n; i++){
init = 3125*init % 65536;
sub(i,j) = (init-32768.0)/16384.0;
}
}
}
DTestRHS::DTestRHS(const DTestMatrix& a) :
DoubleVec(a.rows(), 0.0) {
for(int i=0; i<length(); i++)
(*this)(i) = sum(a.row(i));
}
Total (nonblank) lines = 52
Executable size = 64868 bytes
(Borland C++ V2.0 w. optimizer & 8087, large memory model)
16 MHz 386 w. 80387:
Normalized residual = 1.24482
Residual = .4973799e-13
Machine precision = .2220446e-15
Factorization time = 3.97
Solution time = 0.13
Total time = 4.10
MFLOPS = 0.122
(b)
double precision a(90,90),b(90),x(90)
double precision ops, mflops, norma, normx
double precision resid, residn, eps
double precision t1, t2, total
integer ipvt(90)
double precision second
double precision epslon
lda = 90
n = 90
ops = (2.0e0*n**3)/3.0e0 + 2.0e0*n**2
call matgen(a,lda,n,b,norma)
t1 = second()
call dgefa(a,lda,n,ipvt,info)
t1 = second() -t1
t2 = second()
call dgesl(a,lda,n,ipvt,b,0)
t2 = second() - t2
total = t1+t2
mflops = ops/(1.0e6*total)
do 10 i = 1,n
x(i) = b(i)
10 continue
call matgen(a,lda,n,b,norma)
do 20 i = 1,n
b(i) = -b(i)
20 continue
CALL DMXPY(n,b,n,lda,x,a)
RESID = 0.0
NORMX = 0.0
DO 30 I = 1,N
RESID = amax1( RESID, ABS(b(i)) )
NORMX = amax1( NORMX, ABS(X(I)) )
30 CONTINUE
eps = epslon(1.0D0)
RESIDn = RESID/( N*NORMA*NORMX*EPS )
write(6,1000)RESIDn
1000 format(' Normalized residual =', g16.7)
write(6,1001)RESID
100 format(' Residual = ', g16.7)
write(6,1002)eps
1002 format(' Machine precision = ', g16.7)
write(6,1003)t1
1003 format(' Factorization time = ', g16.7)
write(6,1004)t2
1004 format(' Solution time = ', g16.7)
write(6,1005)total
1005 format(' Total time = ', g16.7)
write(6,1006)mflops
1006 format(' MFLOPS = ', g16.7)
stop
end
subroutine matgen(a,lda,n,b,norma)
double precision a(lda,1),b(1),norma
init = 1325
norma = 0.0
do 30 j = 1,n
do 20 i = 1,n
init = mod(3125*init,65536)
a(i,j) = (init - 32768.0)/16384.0
norma = amax1(a(i,j), norma)
20 continue
30 continue
do 35 i = 1,n
b(i) = 0.0
35 continue
do 50 j = 1,n
do 40 i = 1,n
b(i) = b(i) + a(i,j)
40 continue
50 continue
return
end
Total (nonblank) lines = 71
Executable size = 87482 bytes
(Microsoft Fortran V5.0 w. optimizer & 8087)
16 MHz 386 w. 80387:
Normalized residual = 1.212636
Residual = .4843265E-13
Machine precision = .2220446E-15
Factorization time = 4.230000
Solution time = .170000
Total time = 4.400000
MFLOPS = .1141364